package wangwenjun.phase2.concurrencypattern.threadcontext;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import util.ThreadUtil;
import wangwenjun.phase2.concurrencypattern.threadcontext.context2.Configuration;
import wangwenjun.phase2.concurrencypattern.threadcontext.context2.OtherResource;
import wangwenjun.phase2.concurrencypattern.threadcontext.context2.ThreadContextV1;
import wangwenjun.phase2.concurrencypattern.threadcontext.context2.ThreadContextV2;

import java.util.stream.IntStream;

/**
 * @author ChangLiang
 * @date 2020/6/15
 */
@Slf4j
public class ThreadLocalTest {

    @Test
    @DisplayName("test")
    public void test() {
        // 全局唯一的ThreadLocal
        ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
        // 这10个线程不会相互影响 每个线程存入threadLocal中的i值是彼此独立的
        IntStream.range(0, 10).forEach(i -> new Thread(() -> {
            threadLocal.set(i);
            log.info("Thread:{} set i = {}", Thread.currentThread(), i);
            ThreadUtil.sleepForMilliSeconds(1_000);
            log.warn("Thread:{} get i = {}", Thread.currentThread(), i);
        }, "my-thread" + i).start());
    }

    @Test
    @DisplayName("test threadlocal memory leak")
    public void test2() throws InterruptedException {
        ThreadLocal<byte[]> threadLocal = new ThreadLocal<>();
        ThreadUtil.sleepForMilliSeconds(15_000);
        threadLocal.set(new byte[1024 * 1024 * 100]);
        threadLocal = null;
        Thread.currentThread().join();
    }

    @Test
    @DisplayName("test context2 threadContextV1")
    public void test3(){
        IntStream.range(0, 10).forEach(i -> new Thread(() -> {
            // 每一个线程 都 new一个新的Configuration
            ThreadContextV1.get().setConfiguration(new Configuration());
            log.info(ThreadContextV1.get().getConfiguration().toString());
        }, "my-thread" + i).start());
    }

    @Test
    @DisplayName("test context2 threadContextV2")
    public void test4(){
        IntStream.range(0, 10).forEach(i -> new Thread(() -> {
            // 每一个线程 都 new一个新的Configuration
            ThreadContextV2.setConfiguration(new Configuration());
            log.info(ThreadContextV2.getConfiguration().toString());

            ThreadContextV2.setOtherResource(new OtherResource());
            log.warn(ThreadContextV2.getOtherResource().toString());
        }, "my-thread" + i).start());
    }
}
